package edu.stanford.prpl.impl.directory;

import static edu.stanford.prpl.common.PRPLConstants.PRPL_X_REQUEST_DEFAULT_TIMEOUT;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.xmlrpc.XmlRpcException;
import org.apache.xmlrpc.client.XmlRpcClient;
import org.apache.xmlrpc.client.XmlRpcClientConfigImpl;

import edu.stanford.prpl.api.Directory;
import edu.stanford.prpl.common.PRPLProperties;

public class DirectoryClient implements Directory<Map<String, String>> {

	private static Log log = LogFactory.getLog(DirectoryClient.class);

	public static DirectoryClient getGlobalDirectoryServiceClient() throws MalformedURLException {
		URL globalDirUrl = new URL(PRPLProperties.getProperty("prpl.directory.url"));
		DirectoryClient globalDirClient = new DirectoryClient(globalDirUrl, DirectoryCommon.GLOBAL_DIR_API_NAME);
		return globalDirClient;
	}

	private XmlRpcClient xmlRpcClient;
	private String apiName;

	public DirectoryClient(URL hostUrl, String apiName) {
		XmlRpcClientConfigImpl xmlRpcClientConfig = new XmlRpcClientConfigImpl();
		xmlRpcClientConfig.setServerURL(hostUrl);
		xmlRpcClientConfig.setEnabledForExtensions(true);
		xmlRpcClientConfig.setContentLengthOptional(true);
		xmlRpcClientConfig.setConnectionTimeout(PRPL_X_REQUEST_DEFAULT_TIMEOUT);
		xmlRpcClientConfig.setReplyTimeout(PRPL_X_REQUEST_DEFAULT_TIMEOUT);

		this.xmlRpcClient = new XmlRpcClient();
		this.xmlRpcClient.setConfig(xmlRpcClientConfig);
		this.apiName = apiName;
	}

	public DirectoryClient(URL hostUrl, String apiName, String userKey, String userPassword) {
		XmlRpcClientConfigImpl xmlRpcClientConfig = new XmlRpcClientConfigImpl();
		xmlRpcClientConfig.setServerURL(hostUrl);
		xmlRpcClientConfig.setEnabledForExtensions(true);
		xmlRpcClientConfig.setContentLengthOptional(true);
		xmlRpcClientConfig.setConnectionTimeout(PRPL_X_REQUEST_DEFAULT_TIMEOUT);
		xmlRpcClientConfig.setReplyTimeout(PRPL_X_REQUEST_DEFAULT_TIMEOUT);
		xmlRpcClientConfig.setBasicUserName(userKey);
		xmlRpcClientConfig.setBasicPassword(userPassword);

		this.xmlRpcClient = new XmlRpcClient();
		this.xmlRpcClient.setConfig(xmlRpcClientConfig);
		this.apiName = apiName;
	}
	
	//@Override
	public Map<String, String> getEntry(String key) {
		Map<String, String> resp = null;
		try {
			resp = (Map<String, String>) xmlRpcClient.execute(apiName + ".getEntry", new Object[] { key });
		} catch (XmlRpcException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return resp;
	}

	//@Override
	public boolean removeEntry(String key) {
		Boolean resp = false;
		try {
			resp = (Boolean) xmlRpcClient.execute(apiName + ".removeEntry", new Object[] { key });
		} catch (XmlRpcException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return resp;
	}

	//@Override
	public boolean sendHearbeat(String key, Object... objects) {
		// TODO Auto-generated method stub
		return false;
	}

	//@Override
	public boolean updateEntry(String key, Map<String, String> entry) {
		Boolean resp = false;
		try {
			Object[] params = new Object[] { key, entry };
			resp = (Boolean) xmlRpcClient.execute(apiName + ".updateEntry", params);
		} catch (XmlRpcException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return resp;
	}

	public static abstract class DirectoryClientWorker implements Runnable {

		protected DirectoryClient dirClient;
		protected int interval;

		public DirectoryClientWorker(DirectoryClient dirClinet, int interval) {
			this.dirClient = dirClinet;
			this.interval = interval;
		}

		public void run() {

			try {
				while (true) {

					Thread.sleep(interval * 1000);
					this.runTask();
					log.debug("DirectoryClientWorker awakened and performed runTask().");
				}
			} catch (Exception e) {
				e.printStackTrace();
			}

		}

		protected abstract void runTask();

	}

}
